﻿using FrameworkCore.DI;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using FrameworkCore.Constants;
using System.Diagnostics;
using FrameworkCore.Interfaces;
using System.Text.RegularExpressions;
using FrameworkCore.Extensions;
using System.Text;
using FrameworkCore.Models;

namespace NM.Module.Logging.Middleware;

/// <summary>
/// 日志中间件
/// </summary>
public partial class LoggingMiddleware : IMiddleware, ITransientDependency
{
    private readonly ILogger<LoggingMiddleware> _logger;
    private readonly Stopwatch _timer;
    private readonly IGenerateIdService _generateIdService;
    private readonly ICurrentUserService _currentUserService;

    public LoggingMiddleware(
        ILogger<LoggingMiddleware> logger, 
        IGenerateIdService generateIdService,
        ICurrentUserService currentUserService)
    {
        _logger = logger;
        _timer = new Stopwatch();
        _generateIdService = generateIdService;
        _currentUserService = currentUserService;
    }

    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        var id = _generateIdService.GenerateIdAsLong();
        var loggerName = context.Request.Method + " " + context.Request.Path;
        var userAgent = context.Request.Headers["User-Agent"][0];
        var responseHeader = string.Empty;
        var requestHeader = context.Request.Headers.ToJson();
        var responseData = "";
        var requestPath = context.Request.Path;
        var requestParams = string.Empty;
        var requestMethod = context.Request.Method;
        var userName = _currentUserService.UserName ?? "匿名访问";
        var clientIP = context.Connection.RemoteIpAddress?.ToString();
        var statusCode = context.Response.StatusCode;
        var loggerTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
        long elapsedMilliseconds = 0;

        // 复制原始请求体以备后续使用
        var requestBodyStream = new MemoryStream();
        var originalRequestBody = context.Request.Body;
        await originalRequestBody.CopyToAsync(requestBodyStream);
        requestBodyStream.Seek(0, SeekOrigin.Begin);
        var requestBodyText = await new StreamReader(requestBodyStream).ReadToEndAsync();
        context.Request.Body = originalRequestBody; // 将请求体重置为原始状态
        string? requestBody = requestBodyText;

        if (requestPath.StartsWithSegments("/api/Auth/Login")) 
        {
            string pattern = "\"username\":\\s*\"([^\"]*)\"";
            Match match = Regex.Match(requestBody, pattern);
            if (match.Success)
            {
                userName = match.Groups[1].Value;
            }
        }

        if (requestBody.Contains("password"))
        {
            string pattern = @"(""password"":\s*"")(\w+)("")";
            string replacement = @"""password"":""*""";
            requestBody = Regex.Replace(requestBody, pattern, replacement);
        }

        if (requestBody.Contains("confirmPassword"))
        {
            string pattern = @"(""confirmPassword"":\s*"")(\w+)("")";
            string replacement = @"""confirmPassword"":""*""";
            requestBody = Regex.Replace(requestBody, pattern, replacement);
        }

        // 重置请求体
        requestBodyStream.Seek(0, SeekOrigin.Begin);
        context.Request.Body = requestBodyStream;

        // 处理请求
        using (var responseBodyStream = new MemoryStream())
        {
            var originalResponseBody = context.Response.Body;
            context.Response.Body = responseBodyStream;

            try
            {
                requestParams = requestBody;

                if (context.Request.HasFormContentType) 
                {
                    requestParams  = context.Request.Form?.Files?.ToJson();
                }

                _timer.Start();
                await next(context).ConfigureAwait(false);
                _timer.Stop();
                elapsedMilliseconds = _timer.ElapsedMilliseconds;

                elapsedMilliseconds = _timer.ElapsedMilliseconds;
                responseBodyStream.Seek(0, SeekOrigin.Begin);
                var responseBodyText = await new StreamReader(responseBodyStream).ReadToEndAsync();
                // 记录响应头信息
                responseHeader = context?.Response?.Headers?.ToJson();
                var responseBody = responseBodyText;
                responseBody = DecodeUnicodeSequences(responseBody);
                responseBodyStream.Seek(0, SeekOrigin.Begin);
                await responseBodyStream.CopyToAsync(originalResponseBody);

                responseData = responseBody;
            }
            catch (Exception ex)
            {
                var requestName = context.Request.Method + " " + context.Request.Path;
                 userName = _currentUserService.UserName ?? "匿名访问";
                _logger.LogError(ex, "{Request}: {Exception}", requestName, ex.Message);

                context.Response.StatusCode = StatusCodes.Status500InternalServerError;
            }
            finally
            {
                if (context.Request.Path.StartsWithSegments("/api")) 
                {
                    var message = string.Empty;
                    if (!responseData.IsNullOrWhiteSpace())
                    {
                        var result = responseData.ToObject<Result>();
                        message = result.Message;
                        responseData = result.ToJson();
                    }

                    if (context.Response.StatusCode == StatusCodes.Status500InternalServerError)
                    {
                        _logger.LogError(NMessageTemplate.ActivityHistoryLog,
                                id, loggerName, userAgent, responseData, requestParams, requestPath, requestMethod, userName, clientIP, statusCode, message, loggerTime, elapsedMilliseconds, requestHeader, responseHeader);
                    }
                    else
                    {
                        if (elapsedMilliseconds < 500)
                        {
                            _logger.LogInformation(NMessageTemplate.ActivityHistoryLog,
                                id, loggerName, userAgent, responseData, requestParams, requestPath, requestMethod, userName, clientIP, statusCode, message, loggerTime, elapsedMilliseconds, requestHeader, responseHeader);

                        }
                        else
                        {
                            _logger.LogWarning(NMessageTemplate.ActivityHistoryLog,
                                id, loggerName, userAgent, responseData, requestParams, requestPath, requestMethod, userName, clientIP, statusCode, message, loggerTime, elapsedMilliseconds, requestHeader, responseHeader);
                        }
                    }
                }   
            }
        }
    }

    private string DecodeUnicodeSequences(string input)
    {
        if (string.IsNullOrWhiteSpace(input))
        {
            return input;
        }

        // 使用正则表达式匹配所有的Unicode转义序列
        string pattern = @"\\u([0-9a-fA-F]{4})";
        return Regex.Replace(input, pattern, m =>
        {
            // 将匹配的Unicode转义序列转换为实际的Unicode字符
            string hexValue = m.Groups[1].Value;
            int codePoint = Convert.ToInt32(hexValue, 16);
            byte[] utf8Bytes = new byte[sizeof(int)];
            utf8Bytes[0] = (byte)((codePoint & 0xFF0000) >> 16);
            utf8Bytes[1] = (byte)((codePoint & 0xFF00) >> 8);
            utf8Bytes[2] = (byte)(codePoint & 0xFF);
            return Encoding.UTF8.GetString(utf8Bytes);
        });
    }
}
